-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: support both http and grpc for logging #474
base: main
Are you sure you want to change the base?
Conversation
2db9974
to
8999a57
Compare
@pytest.mark.parametrize( | ||
"log_message, extra, expected_log_type", | ||
[ | ||
( | ||
"some log message without extra", | ||
{}, | ||
log_pb2.LogType.LOG, | ||
), | ||
( | ||
"some log message", | ||
{"log_type": LogType.LOG}, | ||
log_pb2.LogType.LOG, | ||
), | ||
( | ||
"some metrics message", | ||
{"log_type": LogType.METRICS}, | ||
log_pb2.LogType.METRICS, | ||
), | ||
], | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
each test case for logging.
try: | ||
_response = self.test_queue.get_nowait() | ||
except Exception as e: | ||
pytest.fail(f"Failed to get a log message from the queue: {e}") | ||
|
||
assert _response.ecu_id == TestLogClient.ECU_ID | ||
assert _response.log_type == expected_log_type | ||
|
||
if _response.log_type == log_pb2.LogType.LOG: | ||
# Extract the message part from the log format | ||
# e.g. [2022-01-01 00:00:00,000][ERROR]-test_log_client:test_log_client:123,some log message | ||
log_format_regex = r"\[.*?\]\[.*?\]-.*?:.*?:\d+,(.*)" | ||
match = re.match(log_format_regex, _response.message) | ||
assert match is not None, "Log message format does not match" | ||
extracted_message = match.group(1) | ||
assert extracted_message == log_message | ||
elif _response.log_type == log_pb2.LogType.METRICS: | ||
# Expect the message to be the same as the input | ||
assert _response.message == log_message | ||
else: | ||
pytest.fail(f"Unexpected log type: {_response.log_type}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
verify each parameter(ecu_id, log_type, message(format/raw)).
for more information, see https://pre-commit.ci
7f1d839
to
7acbe6d
Compare
18eb3bb
to
0a523e2
Compare
0a523e2
to
58a0bad
Compare
@dataclass | ||
class QueueData: | ||
"""Queue data format for logging.""" | ||
|
||
log_type: LogType | ||
message: str |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed queue from str to QueueData
.
@pytest.mark.parametrize( | ||
"test_log_msg, test_extra, expected_log_type", | ||
[ | ||
("emit one logging entry", None, _logging.LogType.LOG), | ||
( | ||
"emit one logging entry", | ||
{"log_type": _logging.LogType.LOG}, | ||
_logging.LogType.LOG, | ||
), | ||
( | ||
"emit one metrics entry", | ||
{"log_type": _logging.LogType.METRICS}, | ||
_logging.LogType.METRICS, | ||
), | ||
], | ||
) | ||
def test_server_logger(test_log_msg, test_extra, expected_log_type): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add test cases for metrics.
class TransmitterFactory: | ||
@staticmethod | ||
def create(logging_upload_endpoint: AnyHttpUrl, ecu_id: str): | ||
try: | ||
_transmitter_grpc = TransmitterGrpc(logging_upload_endpoint, ecu_id) | ||
_transmitter_grpc.check(timeout=3) | ||
return _transmitter_grpc | ||
except Exception: | ||
return TransmitterHttp(logging_upload_endpoint, ecu_id) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Factory Class.
class Transmitter(ABC): | ||
def __init__(self, logging_upload_endpoint, ecu_id: str): | ||
self.ecu_id = ecu_id | ||
|
||
@abstractmethod | ||
def send(self, log_type: LogType, message: str, timeout: int) -> None: | ||
pass | ||
|
||
@abstractmethod | ||
def check(self, timeout: int) -> None: | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Base Class.
class TransmitterGrpc(Transmitter): | ||
def __init__(self, logging_upload_endpoint: AnyHttpUrl, ecu_id: str): | ||
super().__init__(logging_upload_endpoint, ecu_id) | ||
|
||
parsed_url = urlparse(str(logging_upload_endpoint)) | ||
log_upload_endpoint = parsed_url.netloc | ||
channel = grpc.insecure_channel(log_upload_endpoint) | ||
self._stub = log_v1_grpc.OtaClientIoTLoggingServiceStub(channel) | ||
|
||
def send(self, log_type: LogType, message: str, timeout: int) -> None: | ||
pb2_log_type = ( | ||
log_pb2.LogType.METRICS | ||
if log_type == LogType.METRICS | ||
else log_pb2.LogType.LOG | ||
) | ||
log_entry = log_pb2.PutLogRequest( | ||
ecu_id=self.ecu_id, log_type=pb2_log_type, message=message | ||
) | ||
self._stub.PutLog(log_entry, timeout=timeout) | ||
|
||
def check(self, timeout: int) -> None: | ||
# health check | ||
log_entry = log_pb2.HealthCheckRequest(service="") | ||
self._stub.Check(log_entry) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation Class for gRPC.
class TransmitterHttp(Transmitter): | ||
def __init__(self, logging_upload_endpoint: AnyHttpUrl, ecu_id: str): | ||
super().__init__(logging_upload_endpoint, ecu_id) | ||
|
||
_endpoint = f"{str(logging_upload_endpoint).strip('/')}/" | ||
self.log_upload_endpoint = urljoin(_endpoint, ecu_id) | ||
self._session = requests.Session() | ||
|
||
def send(self, log_type: LogType, message: str, timeout: int) -> None: | ||
# support only LogType.LOG | ||
with contextlib.suppress(Exception): | ||
self._session.post(self.log_upload_endpoint, data=message, timeout=timeout) | ||
|
||
def check(self, timeout: int) -> None: | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implementation Class for HTTP.
|
Description
Support both http and grpc for logging.
In addition, support two types(
LOG
andMETRICS
) logging to collect otaclient metrics.Check list
https://tier4.atlassian.net/wiki/spaces/OTA/pages/3481894920/OTA+Metrics
Documents
https://tier4.atlassian.net/wiki/spaces/OTA/pages/3481894920/OTA+Metrics
Changes
LOG
the purpose is to collect execution log. the log will follow
LOG_FORMAT
format.METRICS
the purpose is to collect metrics log. the metrics log is raw format without applying any formatting.
To emit metrics log,
extra
argument and "log_type" key is necessary.Behavior changes
Does this PR introduce behavior change(s)?
Previous behavior
Behavior with this PR
Breaking change
Does this PR introduce breaking change?
Related links & tickets